#include "PEIncludes.h"

#include "PEAliceSoftImageVsp.h"

#include "PEImage.h"

namespace pe
{

	PE_EXPORT int AliceImageVspReadHeader(AliceImageVspHeader* a_Target, PEStream* a_Stream)
	{
		/*VSP_info *v = malloc(sizeof(VSP_info));

		if (v == NULL)
			return NULL;

		v->x = (d[1] << 8) + d[0];
		v->y = (d[3] << 8) + d[2];
		v->width = ((d[5] << 8) + d[4] - v->x) << 3;
		v->height = (d[7] << 8) + d[6] - v->y;
		v->pb = d[9];
		v->p_offset = 0x0a;
		v->d_offset = 0x3a;

		if (v->x < 0 || v->x > 80 || v->y < 0 || v->y > 400 ||
			v->width <= 0 || v->width > 640 || v->height <= 0 || v->height > 400) {
				free(v);
				return NULL;
		}

		return v;*/

		unsigned int size;
		PEStreamGetFileSize(a_Stream, &size);

		byte data[10];
		PEStreamRead(a_Stream, data, 1, 10);
		for (int i = 0; i < 10; i++) { a_Target->data[i] = data[i]; }

		return PE_OK;
	}

	PE_EXPORT int AliceImageVspReadData(AliceImageVsp* a_Target, AliceImageVspHeader* a_Header, PEStream* a_Stream)
	{
		a_Target->header = new AliceImageVspHeader;
		memcpy(a_Target->header, a_Header, sizeof(AliceImageVspHeader));

		a_Target->x      = (a_Header->data[1] << 8) + a_Header->data[0];
		a_Target->y      = (a_Header->data[3] << 8) + a_Header->data[2];
		a_Target->width  = ((a_Header->data[5] << 8) + a_Header->data[4] - a_Target->x) << 3;
		a_Target->height = ((a_Header->data[7] << 8) + a_Header->data[6] - a_Target->y);

		a_Target->pb = a_Header->data[9];
		a_Target->p_offset = 0x0a;
		a_Target->d_offset = 0x3a;

		PEStreamRead(a_Stream, a_Target->palette, sizeof(AliceImageVspColor), 16);

		unsigned int size;
		PEStreamGetFileSize(a_Stream, &size);

		a_Target->data_size = size - 0x3a;
		a_Target->data = new byte[a_Target->data_size];
		PEStreamRead(a_Stream, a_Target->data, 1, a_Target->data_size);

		return PE_OK;
	}

	PE_EXPORT int AliceImageVspToRaw(PEImageRaw* a_Target, AliceImageVsp* a_Image)
	{
		byte* src = a_Image->data;

		PEImageRawCreate(a_Target, a_Image->width, a_Image->height);
		byte* dst = a_Target->data;

		byte* d = src;
		int w = a_Image->width;
		int h = a_Image->height;

		int c, i, l, x, y, pl;
		unsigned char b, b1, b2, b3, mask = 0;
		unsigned char bcb[4][480], bpb[4][480], *bc[4], *bp[4], *p, *loc;

		//p = new unsigned char[w * h];
		p = dst;

		bp[0] = bpb[0];
		bp[1] = bpb[1];
		bp[2] = bpb[2];
		bp[3] = bpb[3];
		bc[0] = bcb[0];
		bc[1] = bcb[1];
		bc[2] = bcb[2];
		bc[3] = bcb[3];

		for (x = 0; x < (w >> 3); x++) 
		{
			for (pl = 0; pl < 4; pl++)
			{
				for (y = 0; y < h;) 
				{
					c = *d++;
					if (c > 7) 
					{
						*(bc[pl] + y) = c;
						y++;
					} 
					else if (c == 0) 
					{
						l = (*d++) + 1;
						memcpy(bc[pl] + y, bp[pl] + y, l);
						y += l;
					} 
					else if (c == 1) 
					{
						l = (*d++) + 1;
						b = *d++;
						memset(bc[pl] + y, b, l);
						y += l;
					} 
					else if (c == 2) 
					{
						l = (*d++) + 1;
						b = *d++;
						b1 = *d++;
						for (i = 0; i < l; i++) 
						{
							*(bc[pl] + y) = b;
							y++;
							*(bc[pl] + y) = b1;
							y++;
						}
					} 
					else if (c == 3) 
					{
						l = (*d++) + 1;
						for (i = 0; i < l; i++) 
						{
							*(bc[pl] + y) = (*(bc[0] + y) ^ mask);
							y++;
						}
						mask = 0;
					} 
					else if (c == 4) 
					{
						l = (*d++) + 1;
						for (i = 0; i < l; i++) 
						{
							*(bc[pl] + y) = (*(bc[1] + y) ^ mask);
							y++;
						}
						mask = 0;
					} 
					else if (c == 5) 
					{
						l = (*d++) + 1;
						for (i = 0; i < l; i++) 
						{
							*(bc[pl] + y) = (*(bc[2] + y) ^ mask);
							y++;
						}
						mask = 0;
					} 
					else if (c == 6)
					{
						mask = 0xff;
					}
					else if (c == 7) 
					{
						*(bc[pl] + y) = *d++;
						y++;
					}
				}

				/* expand planes to packed pixel */
				for (y = 0; y < h; y++) 
				{
					loc = p + y * w + (x << 3);

					b  = bc[0][y];
					b1 = bc[1][y];
					b2 = bc[2][y];
					b3 = bc[3][y];

					byte index[8];

					index[0] = ((b  >> 7) & 1) | ((b1 >> 6) & 2) | ((b2 >> 5) & 4) | ((b3 >> 4) & 8);
					index[1] = ((b  >> 6) & 1) | ((b1 >> 5) & 2) | ((b2 >> 4) & 4) | ((b3 >> 3) & 8);
					index[2] = ((b  >> 5) & 1) | ((b1 >> 4) & 2) | ((b2 >> 3) & 4) | ((b3 >> 2) & 8);
					index[3] = ((b  >> 4) & 1) | ((b1 >> 3) & 2) | ((b2 >> 2) & 4) | ((b3 >> 1) & 8);

					index[4] = ((b  >> 3) & 1) | ((b1 >> 2) & 2) | ((b2 >> 1) & 4) | ((b3     ) & 8);
					index[5] = ((b  >> 2) & 1) | ((b1 >> 1) & 2) | ((b2     ) & 4) | ((b3 << 1) & 8);
					index[6] = ((b  >> 1) & 1) | ((b1     ) & 2) | ((b2 << 1) & 4) | ((b3 << 2) & 8);
					index[7] = ((b      ) & 1) | ((b1 << 1) & 2) | ((b2 << 2) & 4) | ((b3 << 3) & 8);

					for (int i = 0; i < 8; i++)
					{
						AliceImageVspColor& col = a_Image->palette[index[i]];

						dst[y * w + (x << 3) + (i * 4) + 0] = col.r;
						dst[y * w + (x << 3) + (i * 4) + 1] = col.r;
						dst[y * w + (x << 3) + (i * 4) + 2] = col.r;
						dst[y * w + (x << 3) + (i * 4) + 3] = 255;
					}
					
					//dst[y * w + (x << 3) + 1] = a_Image->palette[index[1]];
				}

				/* copy */
				bp[0] = bc[0];
				bp[1] = bc[1];
				bp[2] = bc[2];
				bp[3] = bc[3];
			}
		}

		return PE_OK;

		/*for (dword y = 0; y < a_Image->height; y++)
		{
			for (dword x = 0; x < a_Image->width;)
			{
				if (*src > 7)
				{
					dst[0] = a_Image->palette[*src].r;
					dst[1] = a_Image->palette[*src].g;
					dst[2] = a_Image->palette[*src].b;
					dst[3] = 255;

					x++;
				}
				else if (*src == 1)
				{
					byte l = (*src++) + 1;
					byte b = *src;
					//memset(bc[pl] + y, b, l);
					for (byte i = 0; i < l; i++) 
					{
						dst[i * 4 + 0] = a_Image->palette[b].r;
						dst[i * 4 + 1] = a_Image->palette[b].g;
						dst[i * 4 + 2] = a_Image->palette[b].b;
						dst[i * 4 + 3] = 255;
					}
					x += l;
				}
				else
				{
					dst[0] = 0;
					dst[1] = 0;
					dst[2] = 0;
					dst[3] = 255;

					x++;
				}

				src++;
				dst += 4;
			}
		}*/

		return PE_OK;
	}

	PE_EXPORT int AliceImageVspReadAndDecrypt(PEImageRaw* a_Target, PEStream* a_Stream)
	{
		AliceImageVspHeader header;
		if (AliceImageVspReadHeader(&header, a_Stream) != PE_OK) 
		{ 
			AliceImageVspDeleteHeader(&header);
			PEStreamClose(a_Stream);
			return -1; 
		}

		AliceImageVsp image;
		if (AliceImageVspReadData(&image, &header, a_Stream) != PE_OK) 
		{ 
			AliceImageVspDeleteHeader(&header);
			AliceImageVspDeleteData(&image);
			PEStreamClose(a_Stream);
			return -1; 
		}

		if (AliceImageVspToRaw(a_Target, &image) != PE_OK) 
		{ 
			AliceImageVspDeleteHeader(&header);
			AliceImageVspDeleteData(&image);
			PEStreamClose(a_Stream);
			return -1; 
		}

		AliceImageVspDeleteHeader(&header);
		AliceImageVspDeleteData(&image);
		PEStreamClose(a_Stream);

		return PE_OK;
	}

	PE_EXPORT int AliceImageVspDeleteHeader(AliceImageVspHeader* a_Header)
	{
		PE_STUB();
		return PE_OK;
	}

	PE_EXPORT int AliceImageVspDeleteData(AliceImageVsp* a_Image)
	{
		PE_STUB();
		return PE_OK;
	}

}